package jmine.tec.web.servlet.filter;

import java.io.IOException;
import java.util.concurrent.Callable;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import jmine.tec.utils.date.ChronoBean;
import jmine.tec.web.servlet.BeanFactoryServletFilter;
import jmine.tec.web.servlet.StatusExposingHttpServletResponse;

/**
 * Filtro que coleta metricas de tempo de execucao de requisicoes HTTP que ocorreram com sucesso (200).
 * 
 * @author Marcio Ribeiro (mmr)
 * @created Dec 9, 2011
 */
public class WebAccessTimeFilter extends BeanFactoryServletFilter {
    private String beanName;

    /**
     * Le as configurações.
     * 
     * @param filterConfig configuração do filtro.
     */
    @Override
    public void initialize(FilterConfig filterConfig) {
        this.beanName = this.getParameter(filterConfig, "webTimeCounter", "webTimeCounter");
    }

    /**
     * Não faz nada.
     */
    public void destroy() {
        // vazio
    }

    /**
     * @author Marcio Ribeiro (mmr)
     */
    private class ProcessRequestTask implements Callable<Boolean> {
        private ServletRequest req;

        private StatusExposingHttpServletResponse resp;

        private FilterChain chain;

        /**
         * Construtor.
         * 
         * @param req request.
         * @param resp response.
         * @param chain chain de filtros.
         */
        public ProcessRequestTask(ServletRequest req, StatusExposingHttpServletResponse resp, FilterChain chain) {
            this.req = req;
            this.chain = chain;
            this.resp = resp;
        }

        /**
         * @return <code>true</code> caso a resposta tenha status OK (200), <code>false</code> caso contrario.
         * @throws Exception in case something wrong happens.
         */
        public Boolean call() throws Exception {
            chain.doFilter(this.req, this.resp);
            return this.resp.getStatus() == HttpServletResponse.SC_OK;
        }
    };

    /**
     * Guarda tempo de execucao.
     * 
     * @param request request.
     * @param response resposta.
     * @param chain chain.
     * @throws IOException se o chain lançar essa exceção.
     * @throws ServletException se o chain lançar essa exceção.
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            ChronoBean chrono = this.getBean(this.beanName, ChronoBean.class);
            chrono.trigger(new ProcessRequestTask(request, (StatusExposingHttpServletResponse) response, chain));
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }
}
